<template>
  <div style="height: 100% !important;">
    <div class="codeMirrorHeaderBtn">
      <div class="codeMirrorBtnItem">
        <span>内容类型</span>
        <el-select size="small" class="code-mode-select" v-model="mode"
                   @change="changeMode">
          <el-option v-for="mode in modes"
                     :key="mode.value" :label="mode.label" :value="mode.value">
          </el-option>
        </el-select>
      </div>
      <div class="codeMirrorBtnItem">
        <span class="btnItem" @click="formatFun"><i class="el-icon-refresh"></i>整理格式</span>
      </div>
      <div class="codeMirrorBtnItem">
        <span class="btnItem" @click="searchFun"><i class="el-icon-search"></i>搜索</span>
      </div>
      <!--<h3 @click="aaa">获取内容</h3>-->
      <!--<h3 @click="bbb">格式化</h3>-->
      <!--<h3 @click="ccc">搜索</h3>-->
      <!--<h3 @click="ddd">请求地址</h3>-->
    </div>
    <div class="in-coder-panel">
      <textarea :ref="refName" class="editCode"></textarea>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
  // 引入全局实例
  import _CodeMirror from 'codemirror'

  // 核心样式
  import 'codemirror/lib/codemirror.css'
  // 引入主题后还需要在 options 中指定主题才会生效
  import 'codemirror/theme/base16-dark.css'

  // 需要引入具体的语法高亮库才会有对应的语法高亮效果
  // codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
  // 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ，所以此处才把对应的 JS 提前引入
  import 'codemirror/mode/javascript/javascript.js'
  import 'codemirror/mode/xml/xml.js'

  // 搜索功能包引入
  import 'codemirror/addon/scroll/annotatescrollbar.js'
  import 'codemirror/addon/search/matchesonscrollbar.js'
  import 'codemirror/addon/search/match-highlighter.js'
  import 'codemirror/addon/search/jump-to-line.js'

  import 'codemirror/addon/dialog/dialog.js'
  import 'codemirror/addon/dialog/dialog.css'
  import 'codemirror/addon/search/searchcursor.js'
  import 'codemirror/addon/search/search.js'

  // 折叠
  import 'codemirror/addon/fold/foldgutter.css'
  import 'codemirror/addon/fold/foldcode'
  import 'codemirror/addon/fold/foldgutter'
  import 'codemirror/addon/fold/brace-fold'
  import 'codemirror/addon/fold/comment-fold'

  // 下面这几个引入的主要是验证提示类的,配置里的lint需要设置true,gutters: ['CodeMirror-lint-markers']
  import 'codemirror/addon/lint/lint'
  import 'codemirror/addon/lint/lint.css'
  import 'codemirror/addon/lint/json-lint'
  import 'codemirror/addon/display/autorefresh' // 及时自动更新，配置里面也需要设置autoRefresh为true

  // 尝试获取全局实例
  const CodeMirror = window.CodeMirror || _CodeMirror

  export default {
    name: 'in-coder',
    props: {
      refName: {
        type: String,
        default: 'textarea'
      },
      // 外部传入的内容，用于实现双向绑定
      value: String,
      // 外部传入的语法类型
      language: {
        type: String,
        default: null
      }
    },
    data() {
      return {
        // 内部真实的内容
        code: '',
        // 默认的语法类型
        mode: 'javascript',
        // 编辑器实例
        coder: null,
        // 默认配置
        options: {
          // 缩进格式
          tabSize: 2,
          styleActiveLine: true,
          // 主题，对应主题库 JS 需要提前引入
          theme: 'base16-dark',
          // 显示行号
          lineNumbers: true,
          lineWrapping: true,
          line: true,
          lint: true,
          foldGutter: true,
          autoRefresh: true,
          gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers']
        },
        // 支持切换的语法高亮类型，对应 JS 已经提前引入
        // 使用的是 MIME-TYPE ，不过作为前缀的 text/ 在后面指定时写死了
        modes: [
          {
            value: 'javascript',
            label: 'Json'
          },
          {
            value: 'html',
            label: 'HTML'
          },
          {
            value: 'XML',
            label: 'XML'
          },
          {
            value: 'text',
            label: 'Text'
          }
        ]
      }
    },
    mounted() {
      // 初始化
      this._initialize()
    },
    methods: {
      aaa() { // 获取值
        console.log(this.code)
      },
      formatFun() { // json字符串格式化
        this.$nextTick(() => {
          this.coder.setValue((JSON.stringify(JSON.parse(this.code), null, 2)))
        })
      },
      searchFun() { // 搜索
        this.coder.execCommand('find') // 触发
      },
      ddd() { // 插入内容
        this.coder.replaceSelection('http://www.baidu.com')
      },
      // 初始化
      _initialize() {
        // 初始化编辑器实例，传入需要被实例化的文本域对象和默认配置
        const textarea = this.refName
        this.coder = CodeMirror.fromTextArea(this.$refs[textarea], this.options)
        // 编辑器赋值
        this.coder.setValue(this.value || this.code)

        // 支持双向绑定
        this.coder.on('change', (coder) => {
          this.code = coder.getValue()

          if (this.$emit) {
            this.$emit('input', this.code)
          }
        })

        // 尝试从父容器获取语法类型
        if (this.language) {
          // 获取具体的语法类型对象
          let modeObj = this._getLanguage(this.language)

          // 判断父容器传入的语法是否被支持
          if (modeObj) {
            this.mode = modeObj.label
          }
        }
      },
      // 获取当前语法类型
      _getLanguage(language) {
        // 在支持的语法类型列表中寻找传入的语法类型
        return this.modes.find((mode) => {
          // 所有的值都忽略大小写，方便比较
          let currentLanguage = language.toLowerCase()
          let currentLabel = mode.label.toLowerCase()
          let currentValue = mode.value.toLowerCase()

          // 由于真实值可能不规范，例如 java 的真实值是 x-java ，所以讲 value 和 label 同时和传入语法进行比较
          return currentLabel === currentLanguage || currentValue === currentLanguage
        })
      },
      // 更改模式
      changeMode(val) {
        // 修改编辑器的语法配置
        console.log(val)
        if (val === 'text') {
          val = 'XML'
        }
        this.coder.setOption('mode', `text/${val}`)

        // 获取修改后的语法
        let label = this._getLanguage(val).label.toLowerCase()

        // 允许父容器通过以下函数监听当前的语法值
        this.$emit('language-change', label)
      }
    }
  }
</script>

<style lang="scss">
  .in-coder-panel{
    flex-grow: 1;
    display: flex;
    position: relative;
    height: calc(100% - 48px) !important;
  }
  .CodeMirror{
    flex-grow: 1;
    z-index: 1;
  }
  .CodeMirror-code{
    line-height: 19px;
  }
  .code-mode-select{
    max-width: 100px;
  }
  .editCode{
    font-size: 16px;
    line-height: 22px;
  }
  .codeMirrorHeaderBtn{
    display: flex;
    align-items: center;
    margin: 16px 0px;
    margin-top: 0;
  }
  .codeMirrorBtnItem{
    margin-left: 20px;
  }
  .codeMirrorBtnItem:first-child{
  }
  .codeMirrorBtnItem .btnItem:hover{
    color: #005A9E;
  }
  .codeMirrorBtnItem span{
    font-size: 14px;
    cursor: pointer;
  }
  .codeMirrorBtnItem i{
    display: inline-block;
    vertical-align: middle;
    margin-right: 6px;
  }
  .CodeMirror{
    height: auto !important;
  }
</style>
